package com.xpec.c4.codec.h2o;

/**
 * 
 * @author Helo Yi
 *
 */
public class H2oBuffer {

	/**
	 * 默认大小
	 */
	private static final int DEFAULT_BUFFER_SIZE = 512;

	/**
	 * 每次增长大小
	 */
	private static final int ADD_BUFFER_SIZE = 512;

	private byte[] buffer;
	private int position;

	private byte writeBuffer[] = new byte[8];
	private byte readBuffer[] = new byte[8];

	protected H2oBuffer() {
		buffer = new byte[DEFAULT_BUFFER_SIZE];
		position = 0;
	}

	protected H2oBuffer(byte[] b) {
		buffer = b;
		position = 0;
	}
	
	protected void put(int v) {
		resizeBuffer(position, buffer.length);

		buffer[position++] = (byte) v;
	}

	protected byte get() {
		return buffer[position++];
	}

	protected void put(byte[] b) {
		resizeBuffer(position + b.length, buffer.length);

		for (byte c : b) {
			buffer[position++] = c;
		}
	}
	
	protected void get(byte[] b) {
		for (int i = 0; i < b.length; i++) {
			b[i] = get();
		}
	}
	
	protected void putFloat(float v) {
		int vi = Float.floatToIntBits(v);
		put((vi >>> 24) & 0xFF);
		put((vi >>> 16) & 0xFF);
		put((vi >>> 8) & 0xFF);
		put((vi >>> 0) & 0xFF);
	}

	protected float getFloat() {
		int ch1 = get()& 0xFF;
		int ch2 = get()& 0xFF;
		int ch3 = get()& 0xFF;
		int ch4 = get()& 0xFF;
		int  ch=  ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
		return Float.intBitsToFloat(ch);
	}

	protected void putDouble(double v) {
		long vl = Double.doubleToLongBits(v);
		
		writeBuffer[0] = (byte) (vl >>> 56);
		writeBuffer[1] = (byte) (vl>>> 48);
		writeBuffer[2] = (byte) (vl >>> 40);
		writeBuffer[3] = (byte) (vl >>> 32);
		writeBuffer[4] = (byte) (vl >>> 24);
		writeBuffer[5] = (byte) (vl >>> 16);
		writeBuffer[6] = (byte) (vl >>> 8);
		writeBuffer[7] = (byte) (vl >>> 0);
		put(writeBuffer);
	}
	
	protected final double getDouble() {
		get(readBuffer);
		
		long l =  (((long) readBuffer[0] << 56) + ((long) (readBuffer[1] & 0xFF) << 48)
				+ ((long) (readBuffer[2] & 0xFF) << 40) + ((long) (readBuffer[3] & 0xFF) << 32)
				+ ((long) (readBuffer[4] & 0xFF) << 24) + ((readBuffer[5] & 0xFF) << 16) + ((readBuffer[6] & 0xFF) << 8) + ((readBuffer[7] & 0xFF) << 0));

		return Double.longBitsToDouble(l);
	}

	protected final int position() {
		return position;
	}
	
	protected void insert(int p, byte[] b, int s) {
		resizeBuffer(p + s , buffer.length);
		
		byte[] old = new byte[position - p];
		System.arraycopy(buffer, p, old, 0, old.length);
		
		position = p;

		for (int i = 0; i < s; i++) {
			put(b[i]);
		}
		
		put(old);
	}

	protected byte[] toBytes() {
		byte[] nb = new byte[position];
		System.arraycopy(buffer, 0, nb, 0, position);
		return nb;
	}

	protected void resizeBuffer(int s1, int s2) {
		if (s1 < s2) {
			return;
		}
		int c = (s1 - s2) / ADD_BUFFER_SIZE + 1;
		
		byte[] nb = new byte[buffer.length + ADD_BUFFER_SIZE * c];
		System.arraycopy(buffer, 0, nb, 0, buffer.length);
		buffer = nb;
	}
}
